package com.example.wordmanage;

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * Word文档节处理器
 * 用于删除包含特定文本的节（section）
 * 
 * @author Generated
 * @version 1.0
 */
public class WordSectionProcessor {
    
    private static final Logger logger = LoggerFactory.getLogger(WordSectionProcessor.class);
    
    /**
     * 要删除的节中包含的标识文本
     */
    private static final String DELETE_MARKER_TEXT = "本节要删除";
    
    /**
     * 删除Word文档中包含特定文本的节
     *
     * @param inputFilePath 输入Word文档的文件路径（相对于项目根目录或绝对路径）
     * @return 新生成Word文档的完整文件路径
     * @throws WordProcessingException 当文档处理过程中发生错误时抛出
     */
    public String deleteSectionsWithText(String inputFilePath) throws WordProcessingException {
        return deleteSectionsWithText(inputFilePath, null, null);
    }

    /**
     * 删除Word文档中包含特定文本的节（支持自定义输出路径和文件名）
     *
     * @param inputFilePath 输入Word文档的文件路径（相对于项目根目录或绝对路径）
     * @param outputDirectory 输出目录路径，如果为null则使用输入文件所在目录
     * @param outputFilePrefix 输出文件名前缀，如果为null则使用默认格式
     * @return 新生成Word文档的完整文件路径
     * @throws WordProcessingException 当文档处理过程中发生错误时抛出
     */
    public String deleteSectionsWithText(String inputFilePath, String outputDirectory, String outputFilePrefix) throws WordProcessingException {
        validateInputPath(inputFilePath);
        
        Path inputPath = resolveFilePath(inputFilePath);
        validateFileExists(inputPath);
        
        try {
            logger.info("开始处理Word文档: {}", inputPath.toAbsolutePath());
            
            // 读取Word文档
            XWPFDocument document = loadDocument(inputPath);
            
            // 处理文档节
            int deletedSections = processSections(document);
            
            // 生成输出文件路径
            String outputFilePath = generateOutputFilePath(inputPath, outputDirectory, outputFilePrefix);

            // 保存处理后的文档
            saveDocument(document, outputFilePath);
            
            logger.info("文档处理完成。删除了 {} 个节，输出文件: {}", deletedSections, outputFilePath);
            
            return outputFilePath;
            
        } catch (IOException e) {
            throw new WordProcessingException("文档读写过程中发生错误: " + e.getMessage(), e);
        } catch (Exception e) {
            throw new WordProcessingException("文档处理过程中发生未知错误: " + e.getMessage(), e);
        }
    }
    
    /**
     * 验证输入文件路径
     */
    private void validateInputPath(String inputFilePath) throws WordProcessingException {
        if (inputFilePath == null || inputFilePath.trim().isEmpty()) {
            throw new WordProcessingException("输入文件路径不能为空");
        }
    }
    
    /**
     * 解析文件路径（支持相对路径和绝对路径）
     */
    private Path resolveFilePath(String filePath) {
        Path path = Paths.get(filePath);
        if (path.isAbsolute()) {
            return path;
        } else {
            // 相对于项目根目录
            return Paths.get(System.getProperty("user.dir")).resolve(path);
        }
    }
    
    /**
     * 验证文件是否存在且为.docx格式
     */
    private void validateFileExists(Path filePath) throws WordProcessingException {
        if (!Files.exists(filePath)) {
            throw new WordProcessingException("文件不存在: " + filePath.toAbsolutePath());
        }
        
        if (!Files.isRegularFile(filePath)) {
            throw new WordProcessingException("指定路径不是一个文件: " + filePath.toAbsolutePath());
        }
        
        String fileName = filePath.getFileName().toString().toLowerCase();
        if (!fileName.endsWith(".docx")) {
            throw new WordProcessingException("文件必须是.docx格式: " + fileName);
        }
    }
    
    /**
     * 加载Word文档
     */
    private XWPFDocument loadDocument(Path filePath) throws IOException {
        try (FileInputStream fis = new FileInputStream(filePath.toFile())) {
            return new XWPFDocument(fis);
        }
    }
    
    /**
     * 处理文档中的节，删除包含特定文本的节
     *
     * @param document Word文档对象
     * @return 删除的节数量
     */
    private int processSections(XWPFDocument document) {
        List<IBodyElement> bodyElements = document.getBodyElements();
        List<SectionInfo> sections = identifySections(bodyElements);

        logger.debug("识别到 {} 个节", sections.size());

        int deletedCount = 0;

        // 从后往前删除，避免索引变化问题
        for (int i = sections.size() - 1; i >= 0; i--) {
            SectionInfo section = sections.get(i);
            if (containsDeleteMarker(section, bodyElements)) {
                deleteSectionContent(document, section);
                deletedCount++;
                logger.debug("删除第 {} 个节 (body元素索引 {}-{})", i + 1, section.startIndex, section.endIndex);
            }
        }

        return deletedCount;
    }
    
    /**
     * 识别文档中的节
     * 根据分节符将文档划分为多个节
     */
    private List<SectionInfo> identifySections(List<IBodyElement> bodyElements) {
        List<SectionInfo> sections = new ArrayList<>();
        int sectionStart = 0;

        for (int i = 0; i < bodyElements.size(); i++) {
            IBodyElement element = bodyElements.get(i);

            // 只有段落可能包含分节符
            if (element instanceof XWPFParagraph) {
                XWPFParagraph paragraph = (XWPFParagraph) element;

                // 检查段落是否包含分节符
                if (hasSectionBreak(paragraph)) {
                    // 创建一个节（从上一个节开始到当前元素）
                    if (i >= sectionStart) {
                        sections.add(new SectionInfo(sectionStart, i));
                    }
                    sectionStart = i + 1;
                }
            }
        }

        // 添加最后一个节（如果存在）
        if (sectionStart < bodyElements.size()) {
            sections.add(new SectionInfo(sectionStart, bodyElements.size() - 1));
        }

        // 如果没有找到分节符，整个文档作为一个节
        if (sections.isEmpty() && !bodyElements.isEmpty()) {
            sections.add(new SectionInfo(0, bodyElements.size() - 1));
        }

        return sections;
    }
    
    /**
     * 检查段落是否包含分节符
     */
    private boolean hasSectionBreak(XWPFParagraph paragraph) {
        CTSectPr sectPr = paragraph.getCTP().getPPr() != null ? 
                         paragraph.getCTP().getPPr().getSectPr() : null;
        return sectPr != null;
    }
    
    /**
     * 检查节是否包含删除标记文本
     */
    private boolean containsDeleteMarker(SectionInfo section, List<IBodyElement> bodyElements) {
        for (int i = section.startIndex; i <= section.endIndex && i < bodyElements.size(); i++) {
            IBodyElement element = bodyElements.get(i);

            if (element instanceof XWPFParagraph) {
                XWPFParagraph paragraph = (XWPFParagraph) element;
                String text = paragraph.getText();
                if (text != null && text.contains(DELETE_MARKER_TEXT)) {
                    return true;
                }
            } else if (element instanceof XWPFTable) {
                XWPFTable table = (XWPFTable) element;
                if (containsDeleteMarkerInTable(table)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 检查表格是否包含删除标记文本
     */
    private boolean containsDeleteMarkerInTable(XWPFTable table) {
        for (XWPFTableRow row : table.getRows()) {
            for (XWPFTableCell cell : row.getTableCells()) {
                String cellText = cell.getText();
                if (cellText != null && cellText.contains(DELETE_MARKER_TEXT)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    /**
     * 删除节的内容
     */
    private void deleteSectionContent(XWPFDocument document, SectionInfo section) {
        List<IBodyElement> bodyElements = document.getBodyElements();

        // 从后往前删除所有body元素，避免索引变化
        for (int i = section.endIndex; i >= section.startIndex && i < bodyElements.size(); i--) {
            IBodyElement element = bodyElements.get(i);

            if (element instanceof XWPFParagraph) {
                XWPFParagraph paragraph = (XWPFParagraph) element;
                // 在删除前获取文本信息，避免删除后访问无效对象
                String paragraphText = "";
                try {
                    paragraphText = paragraph.getText();
                    if (paragraphText == null) paragraphText = "";
                } catch (Exception e) {
                    paragraphText = "[无法获取文本]";
                }
                document.removeBodyElement(document.getPosOfParagraph(paragraph));
                logger.debug("删除段落: {}", paragraphText);
            } else if (element instanceof XWPFTable) {
                XWPFTable table = (XWPFTable) element;
                // 在删除前获取表格信息
                int rowCount = 0;
                int colCount = 0;
                try {
                    rowCount = table.getRows().size();
                    colCount = rowCount > 0 ? table.getRows().get(0).getTableCells().size() : 0;
                } catch (Exception e) {
                    // 忽略获取信息时的异常
                }
                document.removeBodyElement(document.getPosOfTable(table));
                logger.debug("删除表格: {} 行 {} 列", rowCount, colCount);
            } else {
                // 处理其他类型的body元素
                String elementType = element.getClass().getSimpleName();
                // 通过遍历找到元素位置
                List<IBodyElement> allElements = document.getBodyElements();
                for (int j = 0; j < allElements.size(); j++) {
                    if (allElements.get(j) == element) {
                        document.removeBodyElement(j);
                        logger.debug("删除其他body元素: {}", elementType);
                        break;
                    }
                }
            }
        }
    }
    


    /**
     * 生成输出文件路径（支持自定义输出目录和文件名前缀）
     */
    private String generateOutputFilePath(Path inputPath, String outputDirectory, String outputFilePrefix) {
        // 确定输出目录
        Path outputDir;
        if (outputDirectory != null && !outputDirectory.trim().isEmpty()) {
            outputDir = Paths.get(outputDirectory);
            if (!outputDir.isAbsolute()) {
                outputDir = Paths.get(System.getProperty("user.dir")).resolve(outputDir);
            }
        } else {
            outputDir = inputPath.getParent();
        }

        // 确保输出目录存在
        try {
            Files.createDirectories(outputDir);
        } catch (IOException e) {
            logger.warn("无法创建输出目录: {}, 使用输入文件所在目录", outputDir);
            outputDir = inputPath.getParent();
        }

        // 生成输出文件名
        String outputFileName;
        if (outputFilePrefix != null && !outputFilePrefix.trim().isEmpty()) {
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
            outputFileName = outputFilePrefix + "_" + timestamp + ".docx";
        } else {
            String fileName = inputPath.getFileName().toString();
            String nameWithoutExt = fileName.substring(0, fileName.lastIndexOf('.'));
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
            outputFileName = nameWithoutExt + "_processed_" + timestamp + ".docx";
        }

        return outputDir.resolve(outputFileName).toAbsolutePath().toString();
    }
    
    /**
     * 保存文档到指定路径
     */
    private void saveDocument(XWPFDocument document, String outputPath) throws IOException {
        try (FileOutputStream fos = new FileOutputStream(outputPath)) {
            document.write(fos);
        }
    }
    
    /**
     * 节信息类
     * 用于存储节的起始和结束段落索引
     */
    private static class SectionInfo {
        final int startIndex;
        final int endIndex;
        
        SectionInfo(int startIndex, int endIndex) {
            this.startIndex = startIndex;
            this.endIndex = endIndex;
        }
        
        @Override
        public String toString() {
            return String.format("Section[%d-%d]", startIndex, endIndex);
        }
    }
}
